using DevelopAssistant.AddIn.Diffplex.Properties;
using DevelopAssistant.Service;
using DiffPlex;
using DiffPlex.DiffBuilder;
using DiffPlex.DiffBuilder.Model;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.WinFormsUI.Controls;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing; 
using System.Text; 
using System.Windows.Forms;

namespace DevelopAssistant.AddIn.Diffplex
{
    public partial class MainForm : ICSharpCode.WinFormsUI.Docking.DockContent
    {
        private Form mainForm = null;

        int ScrollType = 0; //0竖向滚动条 1横向滚动条

        int currentIndex = -1;

        int currentVScrollBarValue = 0;
        int currentHScrollBarValue = 0;
        int lastVScrollBarValue = 0;
        int lastHScrollBarValue = 0;

        string currentTheme = string.Empty;
        string HighlightingName = "Text";

        Color red = Color.FromArgb(045, 000, 000);
        Color yellow = Color.FromArgb(153, 153, 0);
        Color green = Color.FromArgb(038, 094, 077);

        string sourceContentText = string.Empty;
        string targetContentText = string.Empty;

        System.Windows.Forms.Timer timer = null;

        List<CodeLine> deffenrence_lines = new List<CodeLine>();

        ToolTip tooltip = new ToolTip();
        OpenFileDialog openFile = new OpenFileDialog();
        ISideBySideDiffBuilder diffBuilder = null;

        public MainForm()
        {
            InitializeComponent();
            InitializeControls();
        }

        public MainForm(Form owner,string theme, AddInBase addin)
            : this()
        {
            mainForm = owner;
            currentTheme = theme;           
            diffBuilder = new DiffPlex.DiffBuilder.SideBySideDiffBuilder(new Differ());

            switch (currentTheme)
            {
                case "Black":
                    red = Color.FromArgb(045, 000, 000);
                    yellow = Color.FromArgb(153, 153, 0);
                    green = Color.FromArgb(038, 094, 077);
                    break;
                case "Default":
                    red = Color.FromArgb(255, 204, 204);
                    yellow = Color.FromArgb(255, 255, 204);
                    green = Color.FromArgb(102, 255, 102);
                    break;
            }

            this.SourceTextControl.SetHighlighting(theme, HighlightingName);
            this.TargetTextControl.SetHighlighting(theme, HighlightingName);

        }

        private void InitializeControls()
        {
            this.lblSourceFile.Text = "原内容";
            this.lblTargetFile.Text = "新内容";
            tooltip.SetToolTip(this.lblSourceFile, "原内容");
            tooltip.SetToolTip(this.lblTargetFile, "新内容");

            this.btnPrevDifferent.ToolTipText = "上一处";
            this.btnNextDifferent.ToolTipText = "下一处";
            this.btnStartCompare.ToolTipText = "开始比较";

            this.btnPrevDifferent.IconImage= Resources.navigate_prev;
            this.btnNextDifferent.IconImage = Resources.navigate_next;
            this.btnStartCompare.IconImage = Resources.compare;

            this.panel3.BorderStyle = NBorderStyle.All;
            this.panel1.BorderColor = SystemColors.ControlLight;           
            this.panel2.BorderStyle = NBorderStyle.Bottom;
            this.panel3.BorderStyle = NBorderStyle.Bottom;
            this.panel2.BorderColor = SystemColors.ControlLight;
            this.panel3.BorderColor = SystemColors.ControlLight;

            this.SourceTextControl.ComparisonState = true;
            this.TargetTextControl.ComparisonState = true;

            this.SourceTextControl.EnableFolding = false;
            this.TargetTextControl.EnableFolding = false;

            this.SourceTextControl.ShowGuidelines = true;
            this.TargetTextControl.ShowGuidelines = true;

            this.SourceTextControl.ActiveTextAreaControl.VScrollBar.ValueChanged += VScrollBar_ValueChanged;
            this.TargetTextControl.ActiveTextAreaControl.VScrollBar.ValueChanged += VScrollBar_ValueChanged;

            this.SourceTextControl.ActiveTextAreaControl.HScrollBar.ValueChanged += HScrollBar_ValueChanged;
            this.TargetTextControl.ActiveTextAreaControl.HScrollBar.ValueChanged += HScrollBar_ValueChanged;

        }

        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            timer.Enabled = false;
            timer.Dispose();
            GC.Collect(0);
            GC.SuppressFinalize(this);
            base.OnFormClosed(e);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            this.comboFontName.SelectedIndex = 0;
            this.splitContainer1.SplitterDistance = this.splitContainer1.Width / 2;             
            this.openFile.Filter = "记事本|*.txt|SQL|*.sql|C Sharp|*.cs|HTML|*.html|XML|.xml|CSS|*.css|JS|*.js|Json|*.json|其他格式|*.*";

            timer = new System.Windows.Forms.Timer();
            timer.Enabled = true;
            timer.Interval = 120;
            timer.Tick += Timer_Tick;

            OnThemeChanged(new EventArgs());
        }

        private void CurrentLightName(string filetype)
        {
            HighlightingName = "Text";
            switch (filetype.ToUpper())
            {
                case ".XML":
                    HighlightingName = "XML";
                    break;
                case ".CONFIG":
                    HighlightingName = "XML";
                    break;
                case ".CSPROJ":
                    HighlightingName = "XML";
                    break;
                case ".CS":
                    HighlightingName = "C#";
                    break;
                case ".JAVA":
                    HighlightingName = "Java";
                    break;
                case ".JSON":
                    HighlightingName = "JavaScript";
                    break;
                case ".JS":
                    HighlightingName = "JavaScript";
                    break;
                case ".SQL":
                    HighlightingName = "TSQL";
                    break;
                case ".HTML":
                    HighlightingName = "HTML";
                    break;
                case ".HTM":
                    HighlightingName = "HTML";
                    break;
                case ".CSHTML":
                    HighlightingName = "CSHTML";
                    break;
                case ".ASPX":
                    HighlightingName = "ASP/XHTML";
                    break;
                case ".CSS":
                    HighlightingName = "CssStyle";
                    break;
                case ".LESS":
                    HighlightingName = "CssStyle";
                    break;
                case ".TXT":
                    HighlightingName = "Text";
                    break;
                case ".ADDIN":
                    HighlightingName = "XML";
                    break;
            }
        }

        private void SynchronScrollbar()
        {
            if (ScrollType == 0 &&
                lastVScrollBarValue == currentVScrollBarValue)
                return;

            if (ScrollType == 1 &&
                lastHScrollBarValue == currentHScrollBarValue)
                return;

            if (ScrollType == 0)
            {
                TargetTextControl.ActiveTextAreaControl.VScrollBar.Value = currentVScrollBarValue;
                SourceTextControl.ActiveTextAreaControl.VScrollBar.Value = currentVScrollBarValue;
                lastVScrollBarValue = currentVScrollBarValue;
            }

            if (ScrollType == 1)
            {
                TargetTextControl.ActiveTextAreaControl.HScrollBar.Value = currentHScrollBarValue;
                SourceTextControl.ActiveTextAreaControl.HScrollBar.Value = currentHScrollBarValue;
                lastHScrollBarValue = currentHScrollBarValue;
            }

            TargetTextControl.ActiveTextAreaControl.UpdateVirtualTop();
            SourceTextControl.ActiveTextAreaControl.UpdateVirtualTop();

            ////文件对比模式则等待其它事件都完成保证同步滚动
            //Application.DoEvents();
        }

        private string GetContent(string path)
        {
            using (System.IO.StreamReader sr = new System.IO.StreamReader(path, Encoding.Default))
            {
                return sr.ReadToEnd();
            }
        }

        private string TrimEnd(string text,string trim)
        {
            if (text.EndsWith(trim))
            {
                text = text.Replace(trim, "\n");
                int trimIndex = text.LastIndexOf('\n');
                text = text.Substring(0, trimIndex);
            }
            if(text.StartsWith(trim))
            {
                text = text.Replace(trim, "\n");
                int trimIndex = text.IndexOf('\n');
                text = text.Substring(trimIndex);
            }
            return text;
        }

        public void OpenFile(string file)
        {
            openFile.FileName = file;
            if (openFile.ShowDialog(this).Equals(DialogResult.OK))
            {
                if (!string.IsNullOrEmpty(openFile.FileName))
                {
                    string context = GetContent(openFile.FileName);
                }
            }
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            SynchronScrollbar();
        }

        private void VScrollBar_ValueChanged(object sender, EventArgs e)
        {
            ScrollType = 0;
            currentVScrollBarValue = ((TextEditorVScrollBar)sender).Value;
        }

        private void HScrollBar_ValueChanged(object sender, EventArgs e)
        {
            ScrollType = 1;
            currentHScrollBarValue = ((TextEditorHScrollBar)sender).Value;
        }

        private void SelectOpenFile(object sender, EventArgs e)
        {
            if (openFile.ShowDialog(this).Equals(DialogResult.OK))
            {
                if (!string.IsNullOrEmpty(openFile.FileName))
                {
                    string fileType = openFile.FileName;
                    fileType = fileType.Substring(fileType.LastIndexOf("."));
                    CurrentLightName(fileType);

                    string fileName= openFile.FileName;
                    fileName = fileName.Substring(fileName.LastIndexOf("\\") + 1);

                    Control control = (Control)sender;
                    string context = GetContent(openFile.FileName);
                    switch (control.Name)
                    {
                        case "lblFile1":
                            SourceTextControl.Text = context;
                            lblSourceFile.Text = "文件一：" + fileName;
                            tooltip.SetToolTip(lblSourceFile, openFile.FileName);
                            break;
                        case "lblFile2":
                            TargetTextControl.Text = context;
                            lblTargetFile.Text = "文件二：" + fileName;
                            tooltip.SetToolTip(lblTargetFile, openFile.FileName);
                            break;
                    }

                    this.SourceTextControl.ActiveTextAreaControl.LineCustomColorsClear();
                    this.TargetTextControl.ActiveTextAreaControl.LineCustomColorsClear();
                    this.SourceTextControl.SetHighlighting(currentTheme, HighlightingName);
                    this.TargetTextControl.SetHighlighting(currentTheme, HighlightingName);

                }
            }
        }

        private void comboFontName_SelectedIndexChanged(object sender, EventArgs e)
        {
            var item = ((NComboBox)sender).SelectedItem;
            SourceTextControl.Font = new Font(item + "", 12.0f);
            TargetTextControl.Font = new Font(item + "", 12.0f);
        }

        private void btnApply_Click(object sender, EventArgs e)
        {
            sourceContentText = SourceTextControl.Text;
            targetContentText = TargetTextControl.Text;
            DiffPlexViewer(diffBuilder.BuildDiffModel(sourceContentText, targetContentText));
        }

        private void btnNextDifferent_Click(object sender, EventArgs e)
        {
            if (deffenrence_lines.Count == 0)
                return;

            currentIndex = currentIndex + 1;
            if (currentIndex > deffenrence_lines.Count - 1)
            {
                currentIndex = deffenrence_lines.Count - 1;
            }
            int lineNumber = deffenrence_lines[currentIndex].LineNumber;
            SourceTextControl.ActiveTextAreaControl.JumpTo(lineNumber);
            TargetTextControl.ActiveTextAreaControl.JumpTo(lineNumber);
        }

        private void btnPrevDifferent_Click(object sender, EventArgs e)
        {
            if (deffenrence_lines.Count == 0)
                return;

            currentIndex = currentIndex - 1;
            if (currentIndex <= 0)
            {
                currentIndex = 0;
            }
            int lineNumber = deffenrence_lines[currentIndex].LineNumber;
            SourceTextControl.ActiveTextAreaControl.JumpTo(lineNumber);
            TargetTextControl.ActiveTextAreaControl.JumpTo(lineNumber);
        }

        private void DiffPlexViewer(SideBySideDiffModel diff)
        {
            currentIndex = 0;
            deffenrence_lines.Clear();
            SourceTextControl.ActiveTextAreaControl.LineCustomColorsClear();
            TargetTextControl.ActiveTextAreaControl.LineCustomColorsClear();

            if (diff != null)
            {
                StringBuilder sourceStringBuilder = new StringBuilder();
                StringBuilder targetStringBuilder = new StringBuilder();

                List<DifferenceLine> sourceDifferenceLines = new List<DifferenceLine>();
                List<DifferenceLine> targetDifferenceLines = new List<DifferenceLine>();

                int lineCount = diff.OldText.Lines.Count;
                if (diff.NewText.Lines.Count > lineCount)
                {
                    lineCount = diff.NewText.Lines.Count;
                }

                for (int i = 0; i < lineCount; i++)
                {
                    ChangeType sourceType = diff.OldText.Lines[i].Type;
                    ChangeType targetType = diff.NewText.Lines[i].Type;

                    if (sourceType == ChangeType.Inserted)
                    {
                        DifferenceLine lline = new DifferenceLine(i, green, "Inserted");
                        sourceDifferenceLines.Add(lline);
                    }
                    if (sourceType == ChangeType.Modified)
                    {
                        DifferenceLine lline = new DifferenceLine(i, red, "Modified");
                        sourceDifferenceLines.Add(lline);
                    }
                    if (sourceType == ChangeType.Deleted)
                    {
                        DifferenceLine lline = new DifferenceLine(i, yellow, "Deleted");
                        sourceDifferenceLines.Add(lline);
                    }

                    
                    if (targetType == ChangeType.Inserted)
                    {
                        DifferenceLine lline = new DifferenceLine(i, green, "Inserted");
                        targetDifferenceLines.Add(lline);
                    }
                    if (targetType == ChangeType.Modified)
                    {
                        DifferenceLine lline = new DifferenceLine(i, red, "Modified");
                        targetDifferenceLines.Add(lline);
                    }
                    if (targetType == ChangeType.Deleted)
                    {
                        DifferenceLine lline = new DifferenceLine(i, yellow, "Deleted");
                        targetDifferenceLines.Add(lline);
                    }

                    if (sourceType != ChangeType.Unchanged || targetType != ChangeType.Unchanged)
                    {
                        deffenrence_lines.Add(new CodeLine(i));
                    }

                    sourceStringBuilder.AppendLine(diff.OldText.Lines[i].Text);
                    targetStringBuilder.AppendLine(diff.NewText.Lines[i].Text);
                }

                //SourceTextControl.Text = sourceStringBuilder.ToString().TrimEnd(System.Environment.NewLine.ToCharArray());
                //TargetTextControl.Text = targetStringBuilder.ToString().TrimEnd(System.Environment.NewLine.ToCharArray());
                SourceTextControl.Text = TrimEnd(sourceStringBuilder.ToString(), System.Environment.NewLine);
                TargetTextControl.Text = TrimEnd(targetStringBuilder.ToString(), System.Environment.NewLine);

                foreach (var line in sourceDifferenceLines)
                {
                    SourceTextControl.ActiveTextAreaControl.AddLineCustomColor(new CustomLineColor(Color.Empty, line.LineBackgroundColor,line.Type), line.LineNumber);
                }

                foreach (var line in targetDifferenceLines)
                {
                    TargetTextControl.ActiveTextAreaControl.AddLineCustomColor(new CustomLineColor(Color.Empty, line.LineBackgroundColor, line.Type), line.LineNumber);
                }

            }          
        }

        public override void OnThemeChanged(EventArgs e)
        {
            Color foreColor = SystemColors.WindowText;
            Color backColor = SystemColors.Control;
            Color linkColor = System.Drawing.Color.Blue;
            Color toolBackColor = SystemColors.ControlLight;
            Color textColor = SystemColors.Window;
            Color gridLineColor = SystemColors.ControlLight;
            string themeName = AppSettings.EditorSettings.TSQLEditorTheme;
            switch (themeName)
            {
                case "Default":
                    foreColor = SystemColors.WindowText;
                    backColor = SystemColors.Control;
                    linkColor = System.Drawing.Color.Blue;
                    toolBackColor = Color.FromArgb(246, 248, 250);
                    textColor = SystemColors.Window;
                    gridLineColor = SystemColors.ControlLight;
                    break;
                case "Black":
                    foreColor = Color.FromArgb(240, 240, 240);
                    backColor = Color.FromArgb(045, 045, 048);
                    linkColor = Color.FromArgb(051, 153, 153);
                    toolBackColor = Color.FromArgb(030, 030, 030);
                    textColor = Color.FromArgb(030, 030, 030);
                    gridLineColor = SystemColors.ControlDark;
                    break;
            }

            panel5.ForeColor = foreColor;
            panel5.BackColor = backColor;

            SourceTextControl.SetHighlighting(themeName, HighlightingName);
            TargetTextControl.SetHighlighting(themeName, HighlightingName);

            groupBox1.BackColor = backColor;
            groupBox1.GridLineColor = gridLineColor;

            panel2.ForeColor = foreColor;
            panel3.BackColor = toolBackColor;
            panel3.ForeColor = foreColor;
            panel2.BackColor = toolBackColor;
            lblFile1.ForeColor = linkColor;
            lblFile1.BackColor = toolBackColor;
            lblFile2.ForeColor = linkColor;
            lblFile2.BackColor = toolBackColor;
            lblSourceFile.ForeColor = foreColor;
            lblSourceFile.BackColor = toolBackColor;
            lblTargetFile.ForeColor = foreColor;
            lblTargetFile.BackColor = toolBackColor;
            comboFontName.ForeColor = foreColor;
            comboFontName.BackColor = textColor;
        }

    }
}
